package com.ceair.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ceair.entity.Oauth2ThirdAccount;
import com.ceair.entity.SysAuthority;
import com.ceair.entity.SysRoleAuthority;
import com.ceair.entity.SysUserRole;
import com.ceair.entity.model.security.CustomGrantedAuthority;
import com.ceair.mapper.SysAuthorityMapper;
import com.ceair.mapper.SysRoleAuthorityMapper;
import com.ceair.mapper.SysUserRoleMapper;
import com.ceair.service.IOauth2ThirdAccountService;
import com.ceair.strategy.context.Oauth2UserConverterContext;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangbaohai
 * @ClassName CustomOidcUserService
 * @description: 自定义三方oidc登录用户信息服务
 * @date 2024年11月26日
 * @version: 1.0.0
 */
@Service
@RequiredArgsConstructor
public class CustomOidcUserService extends OidcUserService {

    private final IOauth2ThirdAccountService thirdAccountService;

    private final Oauth2UserConverterContext userConverterContext;

    private final SysUserRoleMapper sysUserRoleMapper;
    private final SysRoleAuthorityMapper sysRoleAuthorityMapper;
    private final SysAuthorityMapper sysAuthorityMapper;

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        // 获取三方用户信息
        OidcUser oidcUser = super.loadUser(userRequest);
        // 转为项目中的三方用户信息
        Oauth2ThirdAccount oauth2ThirdAccount = userConverterContext.convert(userRequest, oidcUser);
        // 检查用户信息
        thirdAccountService.checkAndSaveUser(oauth2ThirdAccount);
        OidcIdToken oidcIdToken = oidcUser.getIdToken();
        // 将loginType设置至attributes中
        LinkedHashMap<String, Object> attributes = new LinkedHashMap<>(oidcIdToken.getClaims());
        // 将RegistrationId当做登录类型
        attributes.put("loginType", userRequest.getClientRegistration().getRegistrationId());
        // 将用户ID放到唯一键就兼容本系统用户和三方系统用户了
        attributes.put("uniqueId", oauth2ThirdAccount.getUniqueId());
        // 重新生成一个idToken
        OidcIdToken idToken = new OidcIdToken(oidcIdToken.getTokenValue(), oidcIdToken.getIssuedAt(),
                oidcIdToken.getExpiresAt(), attributes);
        String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
                .getUserNameAttributeName();

        // 通过用户id查询权限
        List<SysRoleAuthority> roleMenus;
        Set<CustomGrantedAuthority> authorities = Set.of();
        List<SysUserRole> userRoles =
                sysUserRoleMapper.selectList(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId,
                        oauth2ThirdAccount.getUserId()));
        List<Long> rolesId =
                Optional.ofNullable(userRoles).orElse(Collections.emptyList()).stream().map(SysUserRole::getRoleId).toList();
        if (!rolesId.isEmpty()) {
            // 通过角色菜单关联表查出对应的菜单
            roleMenus =
                    sysRoleAuthorityMapper.selectList(Wrappers.lambdaQuery(SysRoleAuthority.class).in(SysRoleAuthority::getRoleId, rolesId));
            List<Long> menusId =
                    Optional.ofNullable(roleMenus).orElse(Collections.emptyList()).stream().map(SysRoleAuthority::getAuthorityId).toList();
            if (!menusId.isEmpty()) {
                // 根据菜单ID查出菜单
                List<SysAuthority> menus = sysAuthorityMapper.selectByIds(menusId);
                authorities =
                        Optional.ofNullable(menus).orElse(Collections.emptyList()).stream().map(SysAuthority::getAuthority).map(CustomGrantedAuthority::new).collect(Collectors.toSet());
            }
        }

        if (!authorities.isEmpty()) {
            // 使用本系统权限覆盖三方权限重新生成oidcUser
            if (StringUtils.hasText(userNameAttributeName)) {
                return new DefaultOidcUser(authorities.stream().toList(), idToken, oidcUser.getUserInfo(), userNameAttributeName);
            }
            return new DefaultOidcUser(authorities.stream().toList(), idToken, oidcUser.getUserInfo());
        } else {
            // 直接使用原三方权限重新生成oidcUser
            if (StringUtils.hasText(userNameAttributeName)) {
                return new DefaultOidcUser(oidcUser.getAuthorities(), idToken, oidcUser.getUserInfo(), userNameAttributeName);
            }
            return new DefaultOidcUser(oidcUser.getAuthorities(), idToken, oidcUser.getUserInfo());
        }


    }

}
